import groovy.json.JsonBuilder

include {
    sniffles2;
    filterCalls;
    sortVCF;
    getVersions;
    report;
} from "../modules/local/wf-human-sv.nf"
include {
    filterBenchmarkVcf;
    intersectBedWithTruthset;
    truvari;
} from "../modules/local/wf-human-sv-eval.nf"
include {
    annotate_vcf as annotate_sv_vcf;
    haploblocks as haploblocks_sv
} from '../modules/local/common.nf'

workflow bam {
    take:
        bam_channel
        reference
        target
        mosdepth_stats
        optional_file
        genome_build
        chromosome_codes
        workflow_params
    main:
        called = variantCall(bam_channel, reference, target, mosdepth_stats, optional_file, genome_build, chromosome_codes)

        // benchmark
        if (params.sv_benchmark) {
            maybe_benchmark_result = runBenchmark(called.vcf, reference, target)
        }
        else {
            maybe_benchmark_result = Channel.empty()
        }

        if (!params.annotation) {
            final_vcf = called.vcf.join(called.vcf_index)

            report = runReport(
                called.vcf.groupTuple(),
                maybe_benchmark_result.ifEmpty(optional_file),
                workflow_params
            )
        }
        else {
            // append '*' to indicate that annotation should be performed on all chr at once
            vcf_for_annotation = called.vcf.join(called.vcf_index).map{ it << '*' }
            // annotate with SnpEff
            final_vcf = annotate_sv_vcf(vcf_for_annotation, genome_build, "sv").annot_vcf
            report = runReport(
                final_vcf.map{meta, vcf, tbi -> [meta, vcf]}.groupTuple(),
                maybe_benchmark_result.ifEmpty(optional_file),
                workflow_params
            )
        }

        // Prepare stuff to emit
        sv_stats_json = report.json
        report = report.html.concat(
            final_vcf.map{meta, vcf, tbi -> [vcf, tbi]},
            maybe_benchmark_result
        )
    
    emit:
        report = report
        sv_stats_json = sv_stats_json
        sniffles_vcf = called.vcf
        for_phasing = final_vcf
}


workflow runBenchmark {
    take:
        vcf
        reference
        target
    main:
        // for benchmarking we bundle a dataset in the SV container in $WFSV_EVAL_DATA_PATH
        // rather than coupling that dataset to the workflow by referring to it here
        //   in a value channel (or similar), we'll instead interpret use of dummy files
        //   as a flag to load from the bundled dataset inside the process scope
        // note we're not using the usual `optional_file` as this will cause an input collision error
        //   instead we just reference some OPTIONAL_FILE.ext that we know don't exist
        //   we can get away with this as the files will never be opened (so don't need to exist)

        // reconcile workflow target BED and benchmark truthset BED
        //   recall if user does not input a BED, one covering all genomic
        //   intervals in the ref is generated by getAllChromosomesBed
        if (params.sv_benchmark_bed) {
            truthset_bed = Channel.fromPath(params.sv_benchmark_bed, checkIfExists: true)
        }
        else {
            truthset_bed = file("OPTIONAL_FILE.bed") // this will trigger process to use bundled benchmark bed
        }
        intersected = intersectBedWithTruthset(target, truthset_bed)

        // load user-provided benchmark data
        if (params.sv_benchmark_vcf) {
            // truvari assumes index is [vcf].tbi
            truthset_vcf = Channel.fromPath(params.sv_benchmark_vcf, checkIfExists: true)
            truthset_tbi = Channel.fromPath(params.sv_benchmark_vcf + '.tbi', checkIfExists: true)
        }
        else {
            // we'll create some non-existent optional files to stage
            // again this will trigger the process to use the bundled benchmark data
            // we use channels here so we can concat them later
            truthset_vcf = Channel.fromPath("OPTIONAL_FILE.vcf.gz", checkIfExists: false)
            truthset_tbi = Channel.fromPath("OPTIONAL_FILE.vcf.gz.tbi", checkIfExists: false)
        }

        // run benchmark
        filtered = filterBenchmarkVcf(vcf)
        truvari(
            reference,
            filtered,
            truthset_vcf.concat(truthset_tbi).toList(),
            intersected.intersected_bed)
    emit:
        json = truvari.out.truvari_json
}


workflow variantCall {
    take:
        bam_channel
        reference
        target_bed
        mosdepth_stats
        optional_file
        genome_build
        chromosome_codes
    main:

        // tandom_repeat bed
        if(params.tr_bed) {
            tr_bed = Channel.fromPath(params.tr_bed, checkIfExists: true)
        } else {
            tr_bed = optional_file
        }

        if (!genome_build) {
            genome_build = Channel.of(null)
        }

        sniffles2(bam_channel, tr_bed, reference, genome_build)
        filterCalls(sniffles2.out.vcf, mosdepth_stats, target_bed, chromosome_codes)
        sortVCF(filterCalls.out.vcf)

    emit:
        vcf = sortVCF.out.vcf_gz
        vcf_index = sortVCF.out.vcf_tbi
}


workflow runReport {
    take:
        vcf
        eval_json
        workflow_params
    main:
        software_versions = getVersions()
        report(
            vcf,
            eval_json,
            software_versions,
            workflow_params
        )
    emit:
        html = report.out.html
        json = report.out.json
}
